#include "ViewportWidget.h"
#include "Widgets/WidgetTree.h"
#include "Widgets/Window.h"
#include "Framework/Application.h"

#include "Asset/EngineDefaultPackage.h"
#include "Mesh/StaticMesh.h"
#include "Render/Widget/RenderWidgets.h"
#include "Render/ForegroundMesh/RenderForegroundMeshInstance.h"
#include "SceneSubsystems/SceneCameraSubsystem.h"
#include "SceneSubsystems/InputComponentManager.h"

#include "Render/RenderContext.h"
#include "Render/PixelObject/RenderPixelObject.h"

#include "PixelObject/PixelObjectMap.h"

RViewportWidget::RViewportWidget()
{
    Mouse=NewWidget<RMouseWidget>(this);
    Mouse->Anchor.Fill(this);

    Keyboard=NewWidget<RKeyboardWidget>(this);
    Mouse->AutoFocusTarget=Keyboard;

    //bind mouse event
    Mouse->OnPressed.BindLambda([this](const SMouseButtonEvent& InMouseEvent)
    {
        if(!Scene)
        {
            return false;
        }

        return Scene->GetSubsystem<RInputComponentManager>()
            ->OnViewportMouseButtonPressed(InMouseEvent,this);
    });

    Mouse->OnReleased.BindLambda([this](const SMouseButtonEvent& InMouseEvent)
    {
        if(!Scene)
        {
            return false;
        }
        return Scene->GetSubsystem<RInputComponentManager>()
            ->OnViewportMouseButtonReleased(InMouseEvent,this);
    });

    Mouse->OnMoved.BindLambda([this](const SMouseButtonEvent& InMouseEvent)
    {
        if(!Scene)
        {
            return false;
        }
        return Scene->GetSubsystem<RInputComponentManager>()
            ->OnViewportMouseMoved(InMouseEvent,this);
    });

    //bind keyboard event
    Keyboard->OnKeyboardInput.Bind([this](const SKeyboardEvent& InKeyboardEvent)
    {
        if(!Scene)
        {
            return false;
        }
        return Scene->GetSubsystem<RInputComponentManager>()
            ->ProcessKeyboardEvent(InKeyboardEvent,this);
    });
    

};

void RViewportWidget::SetScene(RScenePtr InScene)
{
    if(InScene==Scene)
    {
        return;
    }
    Scene=InScene;
}



void RViewportWidget::PaintSelf(uint16_t& InZOrder,const SRect& InClipArea)
{
    if(!Scene)
    {
        return;
    }

    auto _PaintMode=(int)PaintMode.Get();
    if(_PaintMode==(int)EViewportPaintMode::None)
    {
        //不绘制任何东西
        return;
    }

    auto RenderViewport=std::make_shared<SRenderViewportWidget>();
    RenderViewport->Rect=SRect(PresentAbsPosition,PresentSize);
    RenderViewport->ClipRect=InClipArea;
    RenderViewport->ZOrder=InZOrder;
    InZOrder++;

    
    auto& SceneData=RenderViewport->Scenes.Emplace();
    SceneData=std::make_shared<CRenderScene>();
    
    
    if(_PaintMode & (int)EViewportPaintMode::Scene)
    {
        //绘制场景
        Scene->Paint(SceneData.get());
    }

    if(!bForceUseDefaultParameters.Get())
    {
        LastParameters.RawParameters
            =Scene->GetSubsystem<RSceneCameraManager>()
                ->GetSceneCameraParameter();
    }
    else
    {
        LastParameters.RawParameters.ViewportPosition=ViewportPosition.Get();
        LastParameters.RawParameters.ViewportRotation=ViewportRotation.Get();
        LastParameters.RawParameters.ProjectionType=ProjectionType.Get();
        LastParameters.RawParameters.AspectRatio=AspectRatio.Get();
        LastParameters.RawParameters.PerspectiveFOVY=PerspectiveFOVY.Get();
        LastParameters.RawParameters.OrthographicWidth=OrthographicWidth.Get();
        LastParameters.RawParameters.Near=Near.Get();
        LastParameters.RawParameters.Far=Far.Get();
    }  

    LastParameters.ProjectionMatrix=LastParameters.RawParameters.CalculateProjectionMatrix();
    LastParameters.ViewMatrix=LastParameters.RawParameters.CalculateViewMatrix();

    RenderViewport->CameraParameters=LastParameters;

    RenderViewport->AntiAliasingMethod=AntiAliasingMethod;

    //绘制像素对象映射
    auto _PixelObjectMap=PixelObjectMap.Get();
    if(_PixelObjectMap)
    {

        uint32_t PixelObjectMapWidth= PresentSize.X/3;
        uint32_t PixelObjectMapHeight= PresentSize.Y/3;

        if(PixelObjectMapWidth==0
            || PixelObjectMapHeight==0)
        {
            //视口太小，无法创建像素对象映射
        }
        else
        {
            _PixelObjectMap->PixelObjects.Reset();

            RenderViewport->PixelObjects=std::make_shared<CRenderPixelObjectInstanceGroup>();
            RenderViewport->PixelObjects->PixelObjectMap= _PixelObjectMap->GetRenderObject();
            RenderViewport->PixelObjects->MapWidth=PixelObjectMapWidth;
            RenderViewport->PixelObjects->MapHeight=PixelObjectMapHeight;
        }
    }

    //绘制坐标轴
    if( _PaintMode & (int)EViewportPaintMode::Foreground)
    {
        for (int32_t i = 0; i < 3; i++)
        {
            auto AxisMesh=std::make_shared<SRenderForegroundMeshInstance>();
            RenderViewport->ForegroundMeshInstances.Add(AxisMesh);
            
        }

        auto Mesh=REngineDefaultPackage::Get()->GetAxisMesh();
        for(int32_t i=0;i<3;++i)
        {
            assert(Mesh->GetSectionNum()==1);
            RenderViewport->ForegroundMeshInstances[i]->Mesh= Mesh->GetRenderMeshes()[0];
        }

        //set X color to red , Y color to green, Z color to blue
        RenderViewport->ForegroundMeshInstances[0]->Color=SColor(0.6f, 0.02f, 0.0f);
        RenderViewport->ForegroundMeshInstances[1]->Color=SColor(0.14f, 0.40f, 0.0f);
        RenderViewport->ForegroundMeshInstances[2]->Color=SColor(0.025f, 0.20f, 0.85f);
       
        SVec3 Origin=AxisOrigin.Get();
        float Scale=AxisScale.Get();
        SQuat Rotation=AxisRotation.Get();

        RenderViewport->ForegroundMeshInstances[0]->Position=Origin;
        RenderViewport->ForegroundMeshInstances[1]->Position=Origin;
        RenderViewport->ForegroundMeshInstances[2]->Position=Origin;

        //axis mesh is from 0 to +X
        RenderViewport->ForegroundMeshInstances[0]->Rotation=Rotation;
        //rotate 90 degree around Z axis
        RenderViewport->ForegroundMeshInstances[1]->Rotation=Rotation*SQuat(SVec3(0,0,1),CMath::HalfPi);
        //rotate -90 degree around Y axis
        RenderViewport->ForegroundMeshInstances[2]->Rotation=Rotation*SQuat(SVec3(0,1,0),-CMath::HalfPi);
        
        //set scale
        RenderViewport->ForegroundMeshInstances[0]->Scale=SVec3(Scale,Scale,Scale);
        RenderViewport->ForegroundMeshInstances[1]->Scale=SVec3(Scale,Scale,Scale);
        RenderViewport->ForegroundMeshInstances[2]->Scale=SVec3(Scale,Scale,Scale);
    
        if(_PixelObjectMap)
        {
            for(int32_t i=0;i<3;++i)
            {
                auto PixelObject= std::make_shared<CAxisPixelObject>((EAxis)i);
                auto ID=_PixelObjectMap->PixelObjects.Register(PixelObject);

                auto PixelObjectRender= std::make_shared<CRenderPixelObjectInstance>();
                PixelObjectRender->ObjectID=ID;
                PixelObjectRender->ModelMatrix=SMatrix4x4(
                    RenderViewport->ForegroundMeshInstances[i]->Position,
                    RenderViewport->ForegroundMeshInstances[i]->Rotation,
                    RenderViewport->ForegroundMeshInstances[i]->Scale
                );
                PixelObjectRender->Mesh=RenderViewport->ForegroundMeshInstances[i]->Mesh;
                RenderViewport->PixelObjects->ForegroundInstances.Add(PixelObjectRender);
            }
        }
    }

    //绘制碰撞体
    if(_PaintMode & (int)EViewportPaintMode::Collision)
    {
        //绘制物理
        Scene->PaintCollider(SceneData.get());
    }


    PaintRenderWidget(RenderViewport);




}

SVec2 RViewportWidget::SceneToViewport(const SVec3 &InScenePosition) const
{
    return CMath::ProjectSceneToViewport(
        InScenePosition
        ,PresentSize.X
        ,PresentSize.Y
        ,LastParameters.ProjectionMatrix
        ,LastParameters.ViewMatrix);
}

SVec3 RViewportWidget::ViewportToScene(
    const SVec2 &InViewportPosition
    ,SVec3& OutWorldDirection
    ) const
{
    return CMath::DeprojectViewportToScene(
        InViewportPosition
        ,PresentSize.X
        ,PresentSize.Y
        ,LastParameters.ProjectionMatrix
        ,LastParameters.ViewMatrix
        ,OutWorldDirection);
}

std::shared_ptr<CPixelObject> RViewportWidget::QueryPixelObject(const SIntPoint &InPosition)
{
    auto _PixelObjectMap=PixelObjectMap.Get();
    if(!_PixelObjectMap)
    {
        //没有启用像素对象映射
        return nullptr;
    }

    return _PixelObjectMap->QueryPixelObject(InPosition);
}
